use std::collections::HashSet;
use std::hash::{Hash, Hasher};
use std::rc::Rc;
use std::str::FromStr;
use chrono::{DateTime, Local};
use serde_derive::{Deserialize, Serialize};
use serde_repr::{Deserialize_repr, Serialize_repr};
use crate::business::websocket::dto::user_dto::SexEnum;

#[derive(Debug, Clone)]
pub struct ImDepartment {
    pub id: Option<u64>,
    pub current_user_id: String,
    pub code: String,
    pub name: String,
    pub description: Option<String>,
    pub parent_code: Option<String>,
    pub manager_user_id: Option<String>,
    pub other_manager_user_id: Option<HashSet<String>>,
    pub other_manager_user_ids: Option<String>,
    pub status: ImDepartmentStatus,
    pub create_date_time: DateTime<Local>,
    pub update_date_time: DateTime<Local>,
    pub ext1: Option<String>,
    pub ext2: Option<String>,

}

#[derive(Clone, Debug)]
pub struct ImSession {
    pub id: Option<u64>,
    pub current_user_id: String,
    pub name: String,
    pub from_user_id: String,
    pub to_user_id: Option<String>,
    pub server_id: Option<String>,
    pub session_type: ImSessionType,
    pub group_code: Option<String>,
    pub hot_message_total: u32,
    pub lately_message: String,
    pub is_waking: bool,
    pub is_top: bool,
    pub is_disturb: bool,
    pub is_waking2: bool,
    pub is_top2: bool,
    pub is_disturb2: bool,
    pub ext1: Option<String>,
    pub ext2: Option<String>,
    pub status: ImSessionStatus,
    pub create_time: DateTime<Local>,
    pub update_time: DateTime<Local>,

    pub to_user: Option<Rc<ImUser>>,
    pub group: Option<Rc<ImGroup>>,
}

impl PartialEq for ImSession {
    fn eq(&self, other: &Self) -> bool {
        // if self.id.is_some() && other.id.is_some() {
        //     self.id == other.id
        // } else if self.group_code.is_some() && other.group_code.is_some() {
        //     self.group_code == other.group_code
        // } else {
        //     self.to_user_id == other.to_user_id
        // }\
        self.id == other.id && self.name == other.name && self.lately_message == other.lately_message 
         && self.hot_message_total == other.hot_message_total && self.is_waking == other.is_waking
         && self.is_top == other.is_top && self.is_disturb == other.is_disturb && self.is_waking2 == other.is_waking2
         && self.is_top2 == other.is_top2 && self.is_disturb2 == other.is_disturb
         && self.update_time == other.update_time
    }
}

#[derive(Clone, Debug)]
pub struct ImMessage {
    pub id: Option<u64>,
    pub client_id: String,
    pub current_user_id: String,
    pub from_user_id: String,
    pub to_user_id: Option<String>,
    pub server_id: Option<String>,
    pub message_type: MessageType,
    pub group_code: Option<String>,
    pub content: String,
    pub session_id: u64,
    pub ref_type: Option<ImMessageRefType>,
    pub ref_message_ids: Option<String>,
    pub ext: Option<String>,
    pub ext1: Option<String>,
    pub ext2: Option<String>,
    pub version: u64,
    pub status: ImMessageStatus,
    pub file_status: ImMessageFileStatus,
    pub action_status: ImMessageActionStatus,
    pub server_receive_time: Option<DateTime<Local>>,
    pub create_date_time: DateTime<Local>,
    pub update_date_time: DateTime<Local>,

    pub message_send_set: Option<HashSet<ImMessageSend>>,
    pub session: Option<ImSession>,
}

impl PartialEq for ImMessage {
    fn eq(&self, other: &Self) -> bool {
        if self.id.is_some() && other.id.is_some() {
            self.id == other.id
        } else if self.server_id.is_some() && other.server_id.is_some() {
            self.server_id.clone().unwrap() == other.server_id.clone().unwrap()
        } else {
            self.client_id == other.client_id
        }
    }
}

impl ImMessage {
    
    pub fn is_attach_file(&self) -> bool {
        self.message_type.clone() == MessageType::Image || self.message_type.clone() == MessageType::File ||
        self.message_type.clone() == MessageType::Audio || self.message_type.clone() == MessageType::Video
    }
}

#[derive(Clone, Debug)]
pub struct ImMessageSend {
    pub id: Option<u64>,
    pub message_id: Option<u64>,
    pub user_id: String,
    pub status: ImMessageStatus,
    pub file_status: ImMessageFileStatus,
    pub action_status: ImMessageActionStatus,
    pub create_time: DateTime<Local>,
    pub update_time: DateTime<Local>,
}

impl Hash for ImMessageSend {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.user_id.clone().hash(state);
    }
}

impl PartialEq for ImMessageSend {
    fn eq(&self, other: &Self) -> bool {
        if self.id.is_some() && other.id.is_some() {
            self.id == other.id
        } else {
            &self.user_id == &other.user_id
        }
    }
}

impl Eq for ImMessageSend {}

#[derive(Clone, Debug)]
pub struct ImUser {
    pub id: Option<u64>,
    pub user_id: String,
    pub user_name: String,
    pub mobile: Option<String>,
    pub motto: Option<String>,
    pub head_img: Option<String>,
    pub description: Option<String>,
    pub department_code: Option<String>,
    pub other_department_codes: Option<String>,
    pub status: ImUserStatus,
    pub sex: SexEnum,
    pub ext1: Option<String>,
    pub ext2: Option<String>,
    pub first_letter: Option<String>,
    pub create_date_time: DateTime<Local>,
    pub update_date_time: DateTime<Local>,
}

#[derive(Clone, Debug)]
pub struct ImGroup {
    pub id: Option<u64>,
    pub current_user_id: String,
    pub code: String,
    pub server_id: Option<String>,
    pub name: Option<String>,
    pub owner_id: String,
    pub description: Option<String>,
    pub version: u64,
    pub group_type: ImGroupType,
    pub status: ImGroupStatus,
    pub ext1: Option<String>,
    pub ext2: Option<String>,
    pub first_letter: Option<String>,
    pub create_time: DateTime<Local>,
    pub update_time: DateTime<Local>,

    pub group_users: Option<Vec<ImGroupUser>>,
}

#[derive(Clone, Debug)]
pub struct ImGroupUser {
    pub id: Option<u64>,
    pub group_id: u64,
    pub user_id: String,
    pub user_name: Option<String>,
    pub remark: Option<String>,
    pub is_waking: bool,
    pub is_show_name: bool,
    pub is_top: bool,
    pub is_disturb: bool,
    pub ext1: Option<String>,
    pub ext2: Option<String>,
    pub status: ImGroupUserStatus,
    pub create_time: DateTime<Local>,
    pub update_time: DateTime<Local>,
}

impl Hash for ImGroupUser {
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
        self.user_id.hash(state);
        self.group_id.hash(state);
    }
}

impl PartialEq for ImGroupUser {
    fn eq(&self, other: &ImGroupUser) -> bool {
        self.id == other.id || (self.group_id == other.group_id && self.user_id == other.user_id)
    }
}

impl Eq for ImGroupUser {}

#[derive(Clone, Debug)]
pub struct ImConfig {
    pub id: Option<u64>,
    pub name: String,
    pub current_user_id: String,
    pub content: String,
    pub status: ImConfigStatus,
    pub create_time: DateTime<Local>,
    pub update_time: DateTime<Local>,
}

#[derive(Clone, Debug)]
pub struct ImModule {
    pub id: Option<u64>,
    pub name: String,
    pub description: Option<String>,
    pub no: i32,
    pub status: ImModuleStatus,
    pub create_time: DateTime<Local>,
    pub update_time: DateTime<Local>,

    pub module_items: Option<Vec<ImModuleItem>>,
}

#[derive(Clone, Debug)]
pub struct ImModuleItem {
    pub id: Option<u64>,
    pub module_id: Option<u64>,
    pub name: String,
    pub description: Option<String>,
    pub icon: Option<String>,
    pub url: Option<String>,
    pub params: Option<String>,
    pub no: i32,
    pub status: ImModuleItemStatus,
    pub r#type: ImModuleItemType,
    pub create_time: DateTime<Local>,
    pub update_time: DateTime<Local>,
}

#[derive(Clone, Debug)]
pub struct ImSetting {
    pub id: Option<u64>,
    pub name: String,
    pub current_user_id: String,
    pub description: Option<String>,
    pub value: String,
    pub ext1: Option<String>,
    pub ext2: Option<String>,
    pub create_time: DateTime<Local>,
    pub update_time: DateTime<Local>,
}


#[derive(Clone, Debug)]
pub struct ImLabel {
    pub id: Option<u64>,
    pub current_user_id: String,
    pub server_id: Option<String>,
    pub name: String,
    pub status: ImLabelStatus,
    pub create_time: DateTime<Local>,
    pub update_time: DateTime<Local>,
}

#[derive(Clone, Debug)]
pub struct ImCollect {
    pub id: Option<u64>,
    pub user_id: String,
    pub server_id: Option<String>,
    pub message_id: String,
    pub session_id: String,
    pub content: String,
    pub label_ids: Option<String>,
    pub message_type: MessageType,
    pub status: ImCollectStatus,
    pub create_time: DateTime<Local>,
    pub update_time: DateTime<Local>,
}


#[derive(Clone, Debug)]
pub struct ImMessageActionData {
    pub message_id: u64,
    pub user_id: String,
    pub action_status: ImMessageActionStatus,
}

#[derive(Clone, Debug)]
pub struct ImFeedback {
    pub id: Option<u64>,
    pub user_id: String,
    pub server_id: Option<String>,
    pub title: String,
    pub content: String,
    pub result: Option<String>,
    pub status: ImFeedbackStatus,
    pub create_time: DateTime<Local>,
    pub update_time: DateTime<Local>,
}


#[derive(Clone, Debug)]
pub struct ImSensitiveWord {
    pub id: Option<u64>,
    pub word: String,
    pub status: ImSensitiveWordStatus,
    pub create_time: DateTime<Local>,
    pub update_time: DateTime<Local>,
}





#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub enum MessageType {
    Text,
    Image,
    Web,
    File,
    Html,
    Video,
    RichText,
    Audio,
    Url,
    Chat,
    Group,
}

#[derive(Debug, Clone, Serialize_repr, Deserialize_repr, PartialEq)]
#[repr(u8)]
pub enum ImMessageRefType {
    Ref = 1,
    Transfer = 2,
}

#[derive(Debug, Clone, Serialize_repr, Deserialize_repr, PartialEq)]
#[repr(i8)]
pub enum ImMessageStatus {
    None = 0,
    Created = 1,
    Sended = 3,
    Readed = 5,
    Delete = 9,
    Withdraw = 11,
    Withdrawed = 12,
    Updated = 20,
    Disable = 30,
    ServerDeleted = 50,
    Ref = 60,
    Failure = -100,
    Sending = -10,
}

#[derive(Debug, Clone, Serialize_repr, Deserialize_repr, PartialEq)]
#[repr(u8)]
pub enum ImMessageFileStatus {
    None = 0,
    Created = 1,
    Uploading = 2,
    Uploaded = 3,
    Downloaded = 4,
    Downloading = 5,
}

impl ImMessageStatus {
    pub fn is_withdraw(&self) -> bool {
        *self == ImMessageStatus::Withdraw || *self == ImMessageStatus::Withdrawed
    }
}

#[derive(Debug, Clone, Serialize_repr, Deserialize_repr, PartialEq)]
#[repr(u8)]
pub enum ImMessageActionStatus {
    None = 0,
    Withdraw = 6,
    Withdrawed = 7,
    Delete = 9,
    Deleted = 10,
    Read = 1,
    Readed = 2,
}

impl ImMessageActionStatus {
    pub fn is_withdraw(&self) -> bool {
        *self == ImMessageActionStatus::Withdraw || *self == ImMessageActionStatus::Withdrawed
    }
}

impl FromStr for ImMessageActionStatus {
    type Err = ();

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "none" => Ok(ImMessageActionStatus::None),
            "withdraw" => Ok(ImMessageActionStatus::Withdraw),
            "withdrawed" => Ok(ImMessageActionStatus::Withdrawed),
            "delete" => Ok(ImMessageActionStatus::Delete),
            "deleted" => Ok(ImMessageActionStatus::Deleted),
            "read" => Ok(ImMessageActionStatus::Read),
            "readed" => Ok(ImMessageActionStatus::Readed),
            _ => {
                log::error!("MessageActionStatus is error, {}", s);
                Err(())
            }
        }
    }
}

#[derive(Debug, Clone, Serialize_repr, Deserialize_repr, PartialEq)]
#[repr(u8)]
pub enum ImSessionType {
    Chat = 1,
    Notice = 2,
}

#[derive(Debug, Clone, Serialize_repr, Deserialize_repr, PartialEq)]
#[repr(u8)]
pub enum ImSessionStatus {
    Created = 1,
    Enable = 2,
    Disable = 3,
}

#[derive(Debug, Clone, Serialize_repr, Deserialize_repr, PartialEq)]
#[repr(u8)]
pub enum ImConfigStatus {
    Enable = 1,
    Disable = 2,
}

#[derive(Debug, Clone, Serialize_repr, Deserialize_repr, PartialEq)]
#[repr(u8)]
pub enum ImDepartmentStatus {
    Enable = 1,
    Disable = 2,
}

#[derive(Debug, Clone, Serialize_repr, Deserialize_repr, PartialEq)]
#[repr(u8)]
pub enum ImUserStatus {
    Enable = 1,
    Disable = 2,
}

#[derive(Debug, Clone, Serialize_repr, Deserialize_repr, PartialEq)]
#[repr(u8)]
pub enum ImGroupType {
    Chat = 1,
}

#[derive(Debug, Clone, Serialize_repr, Deserialize_repr, PartialEq)]
#[repr(u8)]
pub enum ImGroupStatus {
    None = 0,
    Enable = 1,
    Disable = 2,
    Dissolution = 3,
    Prohibition = 4,
}

#[derive(Debug, Clone, Serialize_repr, Deserialize_repr, PartialEq)]
#[repr(u8)]
pub enum ImGroupUserStatus {
    Enabled = 1,
    Disable = 2,
    Dissolution = 3,
    Prohibition = 4,
}


#[derive(Debug, Clone, Serialize_repr, Deserialize_repr, PartialEq)]
#[repr(u8)]
pub enum ImModuleStatus {
    Enable = 1,
    Disable = 2,
}

#[derive(Debug, Clone, Serialize_repr, Deserialize_repr, PartialEq)]
#[repr(u8)]
pub enum ImModuleItemStatus {
    Enable = 1,
    Disable = 2,
}

#[derive(Debug, Clone, Serialize_repr, Deserialize_repr, PartialEq)]
#[repr(u8)]
pub enum ImModuleItemType {
    Page = 1,
    Origin = 2,
}

#[derive(Debug, Clone, Serialize_repr, Deserialize_repr, PartialEq)]
#[repr(u8)]
pub enum ImLabelStatus {
    Enable = 1,
    Disable = 2,
}

#[derive(Debug, Clone, Serialize_repr, Deserialize_repr, PartialEq)]
#[repr(u8)]
pub enum ImCollectStatus {
    Enable = 1,
    Disable = 2,
}


#[derive(Debug, Clone, Serialize_repr, Deserialize_repr, PartialEq)]
#[repr(u8)]
pub enum ImFeedbackStatus {
    Enable = 1,
    Delete = 2,
    Processed = 3,
}

#[derive(Debug, Clone, Serialize_repr, Deserialize_repr, PartialEq)]
#[repr(u8)]
pub enum ImSensitiveWordStatus {
    Enable = 1,
    Disable = 2,
}